package demo;

import java.util.concurrent.Future;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;

import demo.hystrix.AccountService;
import demo.model.AccountResponseModel;
import demo.model.CustomerResponseModel;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
@RestController
@RequestMapping("/customer")
public class CustomerService {
	
    public static void main(String[] args) {
    	SpringApplication.run(CustomerService.class);
    }

	@LoadBalanced
	@Bean
	RestTemplate restTemplate() {
		return new RestTemplate();
	}

	@Autowired 
    private RestTemplate restTemplate;
	
	@Value("${demo.serviceId}")
	private String serviceId;
    	
	@RequestMapping(value="/{name}/accounts")
    public ResponseEntity<CustomerResponseModel> getAccounts(@PathVariable String name,@RequestParam String region) throws Exception {
    	
    	CustomerResponseModel response = new CustomerResponseModel();
    	
    	response.setServiceId(serviceId);    	
     	
    	AccountResponseModel payload = this.restTemplate.getForObject("http://account-service/account/list/{name}?region={region}", AccountResponseModel.class,name,region);
    	
    	response.setPayload(payload);
    	    	
    	return ResponseEntity.ok(response);    	
    }	
	

	@Autowired
	private AccountService accountService;
	
	@RequestMapping(value="/hystrix/{name}/accounts")
    public ResponseEntity<CustomerResponseModel> getAccountsHystrix(@PathVariable String name, @RequestParam String region) throws Exception {

		CustomerResponseModel response = new CustomerResponseModel();
    	
    	response.setServiceId(serviceId);    	
     	    	
    	response.setPayload(accountService.getAccounts("hystrix", region));
    	    	
    	return ResponseEntity.ok(response);    	
    }
	
	@RequestMapping(value="/hystrix/cache/{name}/accounts")
    public ResponseEntity<CustomerResponseModel> getAccountsHystrixCache(@PathVariable String name, @RequestParam String region) throws Exception {
    	
		@Cleanup("shutdown")
		HystrixRequestContext context = HystrixRequestContext.initializeContext();
		
    	CustomerResponseModel response = new CustomerResponseModel();
    	
    	response.setServiceId(serviceId);    	
     	
    	//get accounts from account-service and store result in cache
    	log.debug("getAccounts#1:{}", accountService.getAccountsFromCache(name, region));
    	//get accounts from cache
    	log.debug("getAccounts#2:{}", accountService.getAccountsFromCache(name, region));
    	//clear cache
    	accountService.removeCache4GetAccounts(name, region);
    	//get accounts from account-service and store result in cache
    	log.debug("getAccounts#3:{}", accountService.getAccountsFromCache(name, region));
    	//get accounts from cache
    	log.debug("getAccounts#4:{}", accountService.getAccountsFromCache(name, region));
    	
    	response.setPayload(accountService.getAccountsFromCache(name, region));
    	
    	return ResponseEntity.ok(response);    	
    }
	
	@RequestMapping(value="/collapser/{name}/accounts")
    public ResponseEntity<CustomerResponseModel> getAccountsHystrixCollapser(@PathVariable String name, @RequestParam String region) throws Exception {
        
        @Cleanup("shutdown")
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        
        CustomerResponseModel response = new CustomerResponseModel();
        
        response.setServiceId(serviceId);   
        
        Future<AccountResponseModel> future = accountService.getAccounts(new AccountService.AccountServiceParameter(name, region));
        
        response.setPayload(future.get());
                
        return ResponseEntity.ok(response);     
    }
	
	@PreAuthorize("hasRole('ADMIN')")
	@RequestMapping(value = "/security/admin/greeting", method = RequestMethod.GET)
	public String adminGreeting() {
		return "(ADMIN)Greeting from " + serviceId;
    }
    
	@PreAuthorize("hasRole('USER')")
	@RequestMapping(value = "/security/user/greeting", method = RequestMethod.GET)
	public String userGreeting() {
		return "(USER)Greeting from " + serviceId;
    }
	
	@RequestMapping(value = "/greeting", method = RequestMethod.GET)
	public String userGreeting2() {
		return "Greeting from " + serviceId;
    }
}